<?php

class Application_Auth_Storage_Cookie implements Zend_Auth_Storage_Interface
{
    private $_tokenLifetime = 86400; // 1 day by default
    private $_cookieLifetime = 2592000; // 1 month by default

    const COOKIE_KEY = 'auth_token';

    /**
     * Sets lifetime of token in DB (how much time admin session will be alive)
     *
     * @param int $tokenLifetime
     * @return Application_Auth_Storage_Cookie
     * @chainable
     */
    public function setTokenLifetime($tokenLifetime)
    {
        $this->_tokenLifetime = $tokenLifetime;
        return $this;
    }

    /**
     * Sets cookielifetime
     *
     * @param int $cookieLifetime
     * @return Application_Auth_Storage_Cookie
     */
    public function setCookieLifetime($cookieLifetime)
    {
        $this->_cookieLifetime = $cookieLifetime;
        return $this;
    }

    /**
     * @return boolean
     */
    public function isEmpty()
    {
        // This storage cannot be empty, because there is always should
        // be authenticated guest user in the system
        return false;
    }

    /**
     * @param string $contents
     * @return void
     */
    public function write($contents)
    {
        // We will write to storage only when admin authenticates,
        // so $contents will be admin username

        $usersTable = new Application_Model_DbTable_Users();
        $userRow = $usersTable->findByUsername($contents);

        $tokensTable = new Application_Model_DbTable_AuthTokens();

        $user = $this->read();

        $tokenRow = $tokensTable->fetchNew();
        if ($existingToken = $tokensTable->findByToken($user->getAuthToken())) {
            $tokenRow = $existingToken;
        }
        $tokenRow->setFromArray(array(
            'user_id' => $userRow->id,
            'token' => $user->getAuthToken()
        ));
        $tokenRow->setLifetime($this->_tokenLifetime);
        $tokenRow->save();
    }

    /**
     * @return Application_Auth_User
     */
    public function read()
    {
        $this->_deleteExpiredTokens();

        // Have auth token: ok, return user or guest for this token.
        // Dont have: create token for guest
        $userRow = null;
        if ($token = $this->_fetchAuthToken()) {
            if ($tokenRow = $this->_fetchAuthTokenRow()) {
                $userRow = $tokenRow->getUser();
                // Set new expired date when user requests page
                $tokenRow->setLifetime($this->_tokenLifetime);
                $tokenRow->save();
            }
        } else {
            $token = md5(time() + rand());
        }

        // WAT?! ZF has no OO approach to set response cookies
        setcookie(self::COOKIE_KEY, $token, time() + $this->_cookieLifetime);

        return new Application_Auth_User($token, $userRow);
    }

    /**
     * @return null|Zend_Db_Table_Row_Abstract
     */
    private function _fetchAuthTokenRow()
    {
        if (!$token = $this->_fetchAuthToken()) {
            return null;
        }
        $tokensTable = new Application_Model_DbTable_AuthTokens();
        return $tokensTable->findByToken($token);
    }

    private function _fetchAuthToken()
    {
        $request = Zend_Controller_Front::getInstance()->getRequest();
        return $request->getCookie(self::COOKIE_KEY);
    }

    /**
     * @return void
     */
    private function _deleteExpiredTokens()
    {
        $tokensTable = new Application_Model_DbTable_AuthTokens();
        $tokensTable->delete(array('expires_at <= ?' => time()));
    }

    /**
     * @return void
     */
    public function clear()
    {
        // if logged in, cleas user token id database
        if ($tokenRow = $this->_fetchAuthTokenRow()) {
            $tokenRow->delete();
        }
    }
}